<?php

declare(strict_types=1);

namespace app\service\settlement;

use app\model\InvoiceRequest;
use app\model\SellerStatement;
use InvalidArgumentException;
use think\facade\Db;
use think\Paginator;

class InvoiceService
{
    public function __construct(private StatementService $statementService)
    {
    }

    public function paginate(array $filters, int $page, int $pageSize): Paginator
    {
        $query = InvoiceRequest::with(['statement'])
            ->order('id', 'desc');

        if (!empty($filters['statement_id'])) {
            $query->where('statement_id', (int) $filters['statement_id']);
        }

        if (!empty($filters['seller_org_id'])) {
            $query->where('seller_org_id', (int) $filters['seller_org_id']);
        }

        if (array_key_exists('status', $filters) && $filters['status'] !== null && $filters['status'] !== '') {
            $query->where('status', (int) $filters['status']);
        }

        if (!empty($filters['keyword'])) {
            $keyword = trim((string) $filters['keyword']);
            $query->where(function ($subQuery) use ($keyword) {
                $subQuery->whereLike('invoice_no', '%' . $keyword . '%')
                    ->whereOr('invoice_url', 'like', '%' . $keyword . '%');
            });
        }

        return $query->paginate([
            'list_rows' => $pageSize,
            'page' => $page,
        ]);
    }

    public function get(int $id): InvoiceRequest
    {
        $invoice = InvoiceRequest::with(['statement', 'org'])->find($id);
        if (!$invoice) {
            throw new InvalidArgumentException('发票申请不存在');
        }

        return $invoice;
    }

    public function create(array $payload): InvoiceRequest
    {
        $statementId = (int) ($payload['statement_id'] ?? 0);
        if ($statementId <= 0) {
            throw new InvalidArgumentException('账单参数不正确');
        }

        /** @var SellerStatement|null $statement */
        $statement = SellerStatement::find($statementId);
        if (!$statement) {
            throw new InvalidArgumentException('关联账单不存在');
        }

        $sellerOrgId = (int) ($payload['seller_org_id'] ?? 0);
        if ($sellerOrgId <= 0) {
            $sellerOrgId = (int) $statement->seller_org_id;
        }

        if ($sellerOrgId !== (int) $statement->seller_org_id) {
            throw new InvalidArgumentException('账单与卖家组织不匹配');
        }

        $amount = round(max((float) ($payload['amount'] ?? 0), 0), 2);
        if ($amount <= 0) {
            throw new InvalidArgumentException('发票金额必须大于0');
        }

        $taxRate = isset($payload['tax_rate']) ? (float) $payload['tax_rate'] : 0.0;
        $taxAmount = isset($payload['tax_amount'])
            ? round((float) $payload['tax_amount'], 2)
            : round($amount * $taxRate, 2);

        $invoice = Db::transaction(function () use ($statement, $sellerOrgId, $payload, $amount, $taxRate, $taxAmount) {
            $now = date('Y-m-d H:i:s');

            /** @var InvoiceRequest $record */
            $record = InvoiceRequest::create([
                'statement_id' => (int) $statement->id,
                'seller_org_id' => $sellerOrgId,
                'invoice_no' => (string) ($payload['invoice_no'] ?? ''),
                'invoice_type' => (string) ($payload['invoice_type'] ?? 'normal'),
                'amount' => $amount,
                'tax_rate' => $taxRate,
                'tax_amount' => $taxAmount,
                'invoice_url' => (string) ($payload['invoice_url'] ?? ''),
                'status' => InvoiceRequest::STATUS_PENDING,
                'submitted_at' => $now,
            ]);

            return InvoiceRequest::with(['statement', 'org'])->find((int) $record->id);
        });

        return $invoice;
    }

    public function update(InvoiceRequest $invoice, array $payload, int $reviewerId): InvoiceRequest
    {
        $targetStatus = array_key_exists('status', $payload) ? (int) $payload['status'] : null;
        $statusToSync = null;
        $statementSnapshot = null;

        [$updatedInvoice, $statementSnapshot, $statusToSync] = Db::transaction(function () use ($invoice, $payload, $reviewerId, $targetStatus) {
            /** @var InvoiceRequest|null $locked */
            $locked = InvoiceRequest::with(['statement'])->lock(true)->find((int) $invoice->id);
            if (!$locked) {
                throw new InvalidArgumentException('发票申请不存在');
            }

            $statement = $locked->statement;
            if (!$statement) {
                throw new InvalidArgumentException('关联账单不存在');
            }

            if (isset($payload['invoice_no'])) {
                $locked->invoice_no = (string) $payload['invoice_no'];
            }

            if (isset($payload['invoice_type'])) {
                $locked->invoice_type = (string) $payload['invoice_type'];
            }

            if (isset($payload['invoice_url'])) {
                $locked->invoice_url = (string) $payload['invoice_url'];
            }

            if (array_key_exists('amount', $payload)) {
                $amount = round(max((float) $payload['amount'], 0), 2);
                if ($amount <= 0) {
                    throw new InvalidArgumentException('发票金额必须大于0');
                }
                $locked->amount = $amount;
                $locked->tax_amount = isset($payload['tax_amount'])
                    ? round((float) $payload['tax_amount'], 2)
                    : round($amount * (float) ($payload['tax_rate'] ?? $locked->tax_rate), 2);
            }

            if (array_key_exists('tax_rate', $payload)) {
                $locked->tax_rate = (float) $payload['tax_rate'];
                if (!array_key_exists('tax_amount', $payload) && array_key_exists('amount', $payload)) {
                    $locked->tax_amount = round($locked->amount * $locked->tax_rate, 2);
                }
            }

            if (array_key_exists('tax_amount', $payload)) {
                $locked->tax_amount = round((float) $payload['tax_amount'], 2);
            }

            $now = date('Y-m-d H:i:s');

            if ($targetStatus !== null) {
                if (!in_array($targetStatus, [InvoiceRequest::STATUS_PENDING, InvoiceRequest::STATUS_APPROVED, InvoiceRequest::STATUS_REJECTED], true)) {
                    throw new InvalidArgumentException('发票状态不合法');
                }

                if ($targetStatus === InvoiceRequest::STATUS_APPROVED) {
                    $locked->status = InvoiceRequest::STATUS_APPROVED;
                    $locked->reviewer_id = $reviewerId;
                    $locked->reviewed_at = $now;
                    $locked->reject_reason = '';

                    if ((int) $statement->status < SellerStatement::STATUS_WAIT_PAYOUT) {
                        $statusToSync = SellerStatement::STATUS_WAIT_PAYOUT;
                    }
                } elseif ($targetStatus === InvoiceRequest::STATUS_REJECTED) {
                    $rejectReason = (string) ($payload['reject_reason'] ?? '');
                    if ($rejectReason === '') {
                        throw new InvalidArgumentException('驳回原因不能为空');
                    }
                    $locked->status = InvoiceRequest::STATUS_REJECTED;
                    $locked->reviewer_id = $reviewerId;
                    $locked->reviewed_at = $now;
                    $locked->reject_reason = $rejectReason;
                } else {
                    $locked->status = InvoiceRequest::STATUS_PENDING;
                    $locked->reviewer_id = null;
                    $locked->reviewed_at = null;
                    $locked->reject_reason = '';
                }
            }

            $locked->save();

            return [
                InvoiceRequest::with(['statement', 'org'])->find((int) $locked->id),
                SellerStatement::find((int) $statement->id),
                $statusToSync,
            ];
        });

        if ($statusToSync === SellerStatement::STATUS_WAIT_PAYOUT && $statementSnapshot) {
            $this->statementService->transition($statementSnapshot, SellerStatement::STATUS_WAIT_PAYOUT, [], true);
        }

        return $updatedInvoice;
    }
}
